package com.dreamwhale.machinery.pay.weChat.server.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.dreamwhale.machinery.adviceException.DragonException;
import com.dreamwhale.machinery.config.DataResult;
import com.dreamwhale.machinery.dao.DictDetailMapper;
import com.dreamwhale.machinery.dao.UserApplyMapper;
import com.dreamwhale.machinery.dao.VipUserInfoMapper;
import com.dreamwhale.machinery.entity.DictDetail;
import com.dreamwhale.machinery.entity.UserApply;
import com.dreamwhale.machinery.entity.VipUserInfo;
import com.dreamwhale.machinery.goods.entity.YxStoreOrder;
import com.dreamwhale.machinery.goods.mapper.YxStoreOrderMapper;
import com.dreamwhale.machinery.pay.weChat.config.WeChatConfig;
import com.dreamwhale.machinery.pay.weChat.server.WeChatPayServer;
import com.dreamwhale.machinery.pay.weChat.utils.Md5Util;
import com.dreamwhale.machinery.pay.weChat.utils.PrepayIdRequestHandler;
import com.dreamwhale.machinery.pay.weChat.utils.WxNotifyParam;
import com.dreamwhale.machinery.pay.weChat.utils.XMLUtil;
import org.apache.commons.lang3.StringUtils;
import org.jdom2.JDOMException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@Service
public class WeChatServerImpl implements WeChatPayServer {

    @Resource
    private YxStoreOrderMapper yxStoreOrderMapper;

    @Resource
    private UserApplyMapper userApplyMapper;

    @Resource
    private VipUserInfoMapper vipUserInfoMapper;
    @Resource
    private DictDetailMapper dictDetailMapper;

    @Override
    public WxNotifyParam orderPay(String orderId, String body, BigDecimal money, String backJsonInfo, HttpServletRequest request, HttpServletResponse response) {
        PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response);
        int value = money.multiply(BigDecimal.valueOf(100)).intValue();
        prepayReqHandler.setParameter("appid", WeChatConfig.APP_ID);
        prepayReqHandler.setParameter("body", WeChatConfig.BODY);
        prepayReqHandler.setParameter("mch_id", WeChatConfig.MCH_ID);
        String time = Long.toString(System.currentTimeMillis() / 1000);
        String idStr = Long.toString(System.currentTimeMillis());
        prepayReqHandler.setParameter("nonce_str", idStr);
        prepayReqHandler.setParameter("notify_url", WeChatConfig.NOTIFY_URL);
        prepayReqHandler.setParameter("out_trade_no", orderId);
        prepayReqHandler.setParameter("spbill_create_ip", "47.103.22.134");
        prepayReqHandler.setParameter("total_fee", Integer.toString(value));
        prepayReqHandler.setParameter("trade_type", "APP");
        prepayReqHandler.setParameter("time_start", time);
        prepayReqHandler.setParameter("attach", backJsonInfo);


        /**
         * 注意签名（sign）的生成方式，具体见官方文档（传参都要参与生成签名，且参数名按照字典序排序，最后接上APP_KEY,转化成大写）
         */
        prepayReqHandler.setParameter("sign", prepayReqHandler.createMD5Sign());
        prepayReqHandler.setGateUrl(WeChatConfig.GATEURL);
        String prepayid;
        WxNotifyParam param = new WxNotifyParam();

        try {
            prepayid = prepayReqHandler.sendPrepay();
            // 若获取prepayid成功，将相关信息返回客户端
            if (prepayid != null && !prepayid.equals("")) {
                /**
                 * 签名方式与上面类似
                 */
                param.setPrepayid(prepayid);
                String signs = "appid=" + WeChatConfig.APP_ID +
                        "&noncestr=" + idStr +
                        "&package=Sign=WXPay&partnerid=" + WeChatConfig.PARTNER_ID +
                        "&prepayid=" + prepayid +
                        "&timestamp=" + time +
                        "&key=" + WeChatConfig.APP_KEY;
                param.setSign(Md5Util.MD5Encode(signs, "utf8").toUpperCase());
                param.setAppid(WeChatConfig.APP_ID);
                // 与请求prepayId时值一致
                param.setTimestamp(time);
                param.setNoncestr(idStr);
                // 固定常量
                param.setPackages("Sign=WXPay");
                param.setPartnerid(WeChatConfig.PARTNER_ID);
                return param;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public DataResult recharge(BigDecimal money, Integer userId, HttpServletRequest request, HttpServletResponse response) {
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("payType", 0);
        objectObjectHashMap.put("userId", userId);
        WxNotifyParam wxNotifyParam = orderPay(IdWorker.getIdStr(), null, money, JSON.toJSONString(objectObjectHashMap), request, response);
        if (wxNotifyParam != null) {
            return new DataResult(wxNotifyParam);
        }
        return DataResult.build(500, "微信支付出错");
    }

    @Override
    public DataResult order(String orderId, Integer userId, HttpServletRequest request, HttpServletResponse response) {
        YxStoreOrder yxStoreOrder = yxStoreOrderMapper.selectById(orderId);
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("payType", 1);
        objectObjectHashMap.put("userId", userId);
        WxNotifyParam wxNotifyParam = orderPay(yxStoreOrder.getOrderId().toString(), "", yxStoreOrder.getTotalPrice(), JSON.toJSONString(objectObjectHashMap), request, response);
        if (wxNotifyParam != null) {
            return new DataResult(wxNotifyParam);
        }
        return DataResult.build(500, "微信支付出错");
    }

    @Override
    public String notify(HttpServletRequest request, HttpServletResponse response) {

        InputStream inStream = null;
        try {
            inStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            String resultxml = new String(outSteam.toByteArray(), "utf-8");
            Map<String, String> params = XMLUtil.doXMLParse(resultxml);
            outSteam.close();
            inStream.close();
            System.out.println("=====================回调=======================");


            System.out.println("=====================回调=======================");
            Map<String, String> return_data = new HashMap<String, String>();
            if (CollectionUtils.isEmpty(params) || !params.get("return_code").equals("SUCCESS")) {
                return XMLUtil.setXML("FAIL", "return_code不正确");
            } else {

                // ------------------------------
                // 处理业务开始
                // ------------------------------

                String out_trade_no = params.get("out_trade_no");
                String attach = params.get("attach");
                String payType = JSON.parseObject(attach).get("payType").toString();
                String userId = JSON.parseObject(attach).get("userId").toString();

                switch (Integer.parseInt(payType)) {
                    case 0:
                        break;
                    case 1:
                        YxStoreOrder yxStoreOrder = yxStoreOrderMapper.selectOne(new QueryWrapper<YxStoreOrder>().eq("order_id", out_trade_no));
                        yxStoreOrder.setPaid(true);
                        yxStoreOrder.setPayTime(LocalDateTime.now());
                        yxStoreOrderMapper.updateById(yxStoreOrder);
                        System.out.println("订单信息");
                        break;
                    case 2:
                        UserApply applyOrder = userApplyMapper.selectById(new QueryWrapper<UserApply>().eq("apply_order_id", out_trade_no));
                        applyOrder.setApplyPayTime(LocalDateTime.now());
                        userApplyMapper.updateById(applyOrder);
                        Object pid1 = JSON.parseObject(attach).get("pid");
                        //给邀请的人一个奖励
                        if (pid1 != null) {
                            DictDetail dictDetail = dictDetailMapper.selectOne(new QueryWrapper<DictDetail>().eq("label", "applyAwards"));
                            BigDecimal decimal = BigDecimal.valueOf(Integer.parseInt(dictDetail.getValue()));
                            Integer pid = Integer.parseInt(pid1.toString());
                            VipUserInfo userInfo = vipUserInfoMapper.selectById(pid);
                            userInfo.setPayMoney(userInfo.getPayMoney().add(decimal));
                            vipUserInfoMapper.updateById(userInfo);
                        }
                        break;
                    case 3:
                        VipUserInfo vipUserInfo = vipUserInfoMapper.selectById(out_trade_no);
                        vipUserInfo.setPayTime(LocalDateTime.now());
                        vipUserInfoMapper.updateById(vipUserInfo);
                        break;
                }

                // ------------------------------
                // 此处处理订单状态，结合自己的订单数据完成订单状态的更新
                // ------------------------------
                return XMLUtil.setXML("SUCCESS", "OK");
            }

        } catch (IOException | JDOMException e) {
            e.printStackTrace();
            return XMLUtil.setXML("FAIL", "解析出错");
        }
    }

    @Override
    public DataResult refund(String orderId, String reason) {
        if (StringUtils.isBlank(orderId)) {
            throw new DragonException("订单号不正确");
        }
        YxStoreOrder yxStoreOrder = yxStoreOrderMapper.selectOne(new QueryWrapper<YxStoreOrder>().eq("order_id", orderId));
        if (yxStoreOrder == null) {
            throw new DragonException("无此订单信息");
        }
        BigDecimal money = yxStoreOrder.getTotalPrice();
        if (money.doubleValue() <= 0) {
            throw new DragonException("金额必须大于0");
        }
        PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(null, null);
        int value = money.multiply(BigDecimal.valueOf(100)).intValue();
        prepayReqHandler.setParameter("appid", WeChatConfig.APP_ID);
        prepayReqHandler.setParameter("mch_id", WeChatConfig.MCH_ID);
        String time = Long.toString(System.currentTimeMillis() / 1000);
        String idStr = Long.toString(System.currentTimeMillis());
        prepayReqHandler.setParameter("nonce_str", idStr);
        prepayReqHandler.setParameter("out_refund_no", orderId);
        prepayReqHandler.setParameter("out_trade_no", orderId);
        prepayReqHandler.setParameter("total_fee", Integer.toString(value));
        prepayReqHandler.setParameter("refund_fee", Integer.toString(value));
        prepayReqHandler.setParameter("sign", prepayReqHandler.createMD5Sign());
        prepayReqHandler.setGateUrl("https://api.mch.weixin.qq.com/secapi/pay/refund");


        try {
            Map map = prepayReqHandler.sendHttpsPrepay();
            String return_msg = map.get("return_msg").toString();
            String return_code = map.get("return_code").toString();
            if ("OK".equals(return_msg) && "SUCCESS".equals(return_code)) {
                return new DataResult(200, "退款成功", null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new DataResult(300, "退款失败", null);
/**
 * <xml><return_code><![CDATA[SUCCESS]]></return_code>
 * <return_msg><![CDATA[OK]]></return_msg>
 * <appid><![CDATA[wx2c2b128e47d1d645]]></appid>
 * <mch_id><![CDATA[1600317245]]></mch_id>
 * <nonce_str><![CDATA[Cq0fIb7H4ORr7OH9]]></nonce_str>
 * <sign><![CDATA[7902E0F68A2A8E8157B1D5D49820C210]]></sign>
 * <result_code><![CDATA[SUCCESS]]></result_code>
 * <transaction_id><![CDATA[4200000593202007112104596067]]></transaction_id>
 * <out_trade_no><![CDATA[202007111917054300845]]></out_trade_no>
 * <out_refund_no><![CDATA[202007111917054300845]]></out_refund_no>
 * <refund_id><![CDATA[50300305022020071301485679499]]></refund_id>
 * <refund_channel><![CDATA[]]></refund_channel>
 * <refund_fee>810</refund_fee>
 * <coupon_refund_fee>0</coupon_refund_fee>
 * <total_fee>810</total_fee>
 * <cash_fee>810</cash_fee>
 * <coupon_refund_count>0</coupon_refund_count>
 * <cash_refund_fee>810</cash_refund_fee>
 * </xml>
 */
    }

    @Override
    public DataResult orderApply(String orderId, Integer userId, Integer pid, HttpServletRequest request, HttpServletResponse response) {
        UserApply userApply = userApplyMapper.selectById(orderId);
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("payType", 2);
        objectObjectHashMap.put("userId", userId);
        objectObjectHashMap.put("pid", pid);
        WxNotifyParam wxNotifyParam = orderPay(userApply.getApplyOrderId(), "", userApply.getApplyMoney(), JSON.toJSONString(objectObjectHashMap), request, response);
        return new DataResult(wxNotifyParam);
    }

    @Override
    public DataResult vipRecharge(String orderId, Integer userId) {
        VipUserInfo vipUserInfo = vipUserInfoMapper.selectById(orderId);
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("payType", 3);
        objectObjectHashMap.put("userId", userId);
        WxNotifyParam wxNotifyParam = orderPay(vipUserInfo.getPayOrderId(), "", vipUserInfo.getPayMoney(), JSON.toJSONString(objectObjectHashMap), null, null);
        if (wxNotifyParam != null) {
            return new DataResult(wxNotifyParam);
        }
        throw new DragonException("微信支付出错");
    }


}
